package com.dynamic.mybatis.controller;


import com.alibaba.fastjson.JSON;
import com.dynamic.mybatis.context.SpringContextHolder;
import com.dynamic.mybatis.core.builder.DynamicMapperAdapterBuilder;
import com.dynamic.mybatis.core.enums.ReturnType;
import com.dynamic.mybatis.core.metadata.DynamicMappedStatement;
import com.dynamic.mybatis.core.metadata.DynamicXmlMappedStatement;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@RestController("/")
public class DynamicSqlController {


    private Collection<DynamicSqlWebInterceptor> interceptors;
    @PostConstruct
    private void init(){
        interceptors =  SpringContextHolder.get(DynamicSqlWebInterceptor.class);
    }

    @Autowired
    private DynamicSqlSessionTemplate sqlSessionTemplate;

    @RequestMapping("test")
    public Object test(String dmsId) {

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<select id=\"selectTest\" resultType=\"java.util.Map\">select now() where 1=1  <if test=\"select!=null and select!=''\"> and  2=#{select} </if></select>");
        stringBuilder.append("<update id=\"updateTest\"><if test=\"update!=null and update!=''\"> 2=2 </if></update>");
        stringBuilder.append("<insert id=\"insertTest\"><if test=\"insert!=null and insert!=''\"> 2=2 </if></insert>");
        stringBuilder.append("<delete id=\"deleteTest\"><if test=\"delete!=null and delete!=''\"> 2=2 </if></delete>");
        stringBuilder.append("<resultMap id=\"resultMapTest\" type=\"java.util.Map\"> <result column=\"id\" property=\"id\"/></resultMap>");
        //stringBuilder.append("<select id=\"selectTest2\" resultType=\"java.util.Map\">select now() where 1=1  <include refid=\"sqlTest2\"/>  <if test=\"select!=null and select!=''\"> and  2=#{select} </if></select>");
       // stringBuilder.append("<sql id=\"sqlTest2\"> and 2=2 </sql>");
        Map<String,Object> parameter = new HashMap<>();
        parameter.put("select",2);
        DynamicXmlMappedStatement dms = new DynamicXmlMappedStatement.Builder()
                .setId("selectTest")
                .setMappedStatement(stringBuilder.toString())
                .setReturnType(ReturnType.COLLECT)
                .builder();
        Object result = sqlSessionTemplate.executeGenerator(dms,parameter);
        System.out.println(JSON.toJSONString(result));

        return sqlSessionTemplate.execute(dmsId);
    }



    @PostMapping("${dynamic-sql.web.execute.url.prefix:dynamicSql/execute}/{mappedStatementId}")
    public Object executePost(@PathVariable String mappedStatementId,@RequestBody Map<String,Object> parameter){
        return executeInterceptor(mappedStatementId,parameter);
    }

    @GetMapping("${dynamic-sql.web.execute.url.prefix:dynamicSql/execute}/{mappedStatementId}")
    public Object executeGet(@PathVariable String mappedStatementId,@RequestParam Map<String,Object> parameter){
       return executeInterceptor(mappedStatementId,parameter);
    }

    /**
        * @Description: 初始化动态SQL
        * @param parameter
        * @see  com.dynamic.mybatis.core.metadata.DynamicMappedStatement
        *  parameter.mappedStatementId  动态SQL ID 保持唯一
        *  parameter.sqlCommandTypeName 动态SQL类型  see org.apache.ibatis.mapping.SqlCommandType
        *  parameter.dynamicSql 动态SQl
        *  parameter.parameterType 参数类型  同mybatis sql xml parameterType属性
        *  parameter.resultType    结果类型  同mybatis sql xml resultType属性
        *  parameter.resultMap     结果类型  同mybatis sql xml resultMap属性
        *  parameter.mappedStatementAttribute.returnTypeName  返回值类型 类似mybatis mapper接口类返回值类型 see com.dynamic.mybatis.constant.ReturnType
        *  parameter.mappedStatementAttribute.targetDataSourceKey 默认数据源
        *  parameter.mappedStatementAttribute.dataSourceKeys  支持的数据源
     　*/
    @PostMapping("${dynamic-sql.web.generate.url:dynamicSql/generate}")
    public Object generate(Map<String,Object> parameter){
        return generateInterceptor(parameter);
    }


    private DynamicMappedStatement build(Map<String,Object> map){
       return new DynamicMappedStatement.Builder()
                .setId(Objects.toString(map.get("id"),null))
                .setSqlCommandType(Objects.toString(map.get("sqlCommandTypeName"),null))
                .setMappedStatement(Objects.toString(map.get("dynamicSql"),null))
                .setParameterType(Objects.toString(map.get("parameterType"),null))
                .setReturnType(Objects.toString(map.get("returnTypeName"),null))
                .setTargetDataSourceKey(map.get("targetDataSourceKey"))
                .setDynamicDataSourceKeys((Object[]) map.get("dataSourceKeys"))
                .builder();
    }

    private Object executeInterceptor(String mappedStatementId,Map<String,Object> parameter){
        if(interceptors != null){
            for(DynamicSqlWebInterceptor service : interceptors){
                service.executeRequest(parameter);
            }
        }
        Object result = sqlSessionTemplate.execute(mappedStatementId,parameter);
        if(interceptors != null){
            for(DynamicSqlWebInterceptor service : interceptors){
                result = service.executeResponse(result);
            }
        }
        return result;
    }

    private Object generateInterceptor(Map<String,Object> parameter){
        if(interceptors != null){
            for(DynamicSqlWebInterceptor service : interceptors){
                service.generateRequest(parameter);
            }
        }
        DynamicMappedStatement dynamicMappedStatement = build(parameter);
        new DynamicMapperAdapterBuilder(sqlSessionTemplate.getDynamicSqlSession().getSqlSession().getConfiguration()).parser(dynamicMappedStatement);
        Object result = null;
        if(interceptors != null){
            for(DynamicSqlWebInterceptor service : interceptors){
                result = service.generateResponse(dynamicMappedStatement);
            }
        }
        return result;
    }

}